//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.DataLayer
{
    using System;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Collections;
    using System.Collections.Generic;
    partial class User : NamedObject<User>
    {
        private const string SYSTEMUSER = "system";

        private const string ANONYMOUS = "Anonymous";

        public string ImagePath
        {
            get
            {
                return "/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ManagementStudio/user.png";
            }
        }

        public static User Get(string account, Connection c)
        {
            try
            {
                // Return existing user
                return User.Load(account, c);
            }
            catch (RecordNotFoundException)
            {
                // Create new user and returns
                User user = User.Create(account, c);
                user.Save();
                if (!account.ToLower().Equals(SYSTEMUSER))
                {
                    string credential = string.Format("{0}\\{1}", Environment.UserDomainName, account);
                    UserCredential userCredential = UserCredential.Create(credential, CredentialType.Windows, user, c);
                    userCredential.Save();
                    user.Enabled = true;
                }
                else
                {
                    string credential = string.Format("NT Authority\\SYSTEM");
                    UserCredential userCredential = UserCredential.Create(credential, CredentialType.Windows, user, c);
                    userCredential.Save();
                    user.Enabled = true;
                }
                user.Save();
                return user;
            }
        }

        public override void OnBeforeDelete()
        {
            base.OnBeforeDelete();

            // Check for consistency problems
            if (this.Services.Count > 0)
                throw new ObjectInUseException("Object in use by a service", null);
            if (this.Namespaces.Count > 0)
                throw new ObjectInUseException("Object in use by a namespace", null);
        }


        /// <summary>
        /// Retreive the deleted workflows from the registry.
        /// </summary>
        /// <param name="filter"></param>
        /// <returns>Collection of all the deleted workflows.</returns>
        public Collection<Activity> GetDeletedWorkflows(Activity.ISearch.ISearchClause filter)
        {
            Collection<Activity> deletedActivities = null;
            try
            {
                Activity.ISearch searchQuery = Activity.ISearch.Create();
                searchQuery.Query = Activity.ISearch.AND(
                    Activity.ISearch.Type(EnumFieldBase.Condition.Equals, ActivityType.Root),
                    Activity.ISearch.IsDeleted(BooleanField.Condition.Equals, true),
                    Activity.ISearch.OwnerUserPrincipal(ObjectFieldBase.Condition.Equals, this));
                if (null != filter)
                {
                    searchQuery.Query = Activity.ISearch.AND(searchQuery.Query, filter);
                }
                deletedActivities = new Collection<Activity>(Activity.Search(searchQuery, this.Conn));
            }
            catch (RecordNotFoundException)
            {
            }
            return deletedActivities;
        }

        /// <summary>
        /// Fetches all the activity acls for a user.
        /// </summary>
        /// <returns>Collection of activity acls.</returns>
        public Collection<ActivityACL> GetActivityACLs()
        {
            Collection<ActivityACL> activityACLs = null;
            try
            {
                ActivityACL.ISearch searchQuery = ActivityACL.ISearch.Create();
                searchQuery.Query = ActivityACL.ISearch.PrivOwnerUserPrincipal(ObjectFieldBase.Condition.Equals, this);
                activityACLs = new Collection<ActivityACL>(ActivityACL.Search(searchQuery, this.Conn));
            }
            catch (RecordNotFoundException)
            {
            }
            return activityACLs;
        }

        /// <summary>
        ///  Retreive all the currently running jobs schedulded by the user from the registry.
        /// </summary>
        /// <param name="filter">The additional search filter.</param>
        /// <returns>Collection of all the jobs in the registry.</returns>
        public Collection<Job> GetRunningJobs(Job.ISearch.ISearchClause filter)
        {
            Collection<Job> jobList = null;
            Collection<Job> jobListForOwner = new Collection<Job>();
            try
            {
                Job.ISearch searchQuery = Job.ISearch.Create();
                searchQuery.Query = Job.ISearch.AND(
                    Job.ISearch.OR(
                        Job.ISearch.Status(EnumFieldBase.Condition.Equals, JobStatus.Running),
                        Job.ISearch.Status(EnumFieldBase.Condition.Equals, JobStatus.StartPending)
                    ),
                    Job.ISearch.IsDeleted(BooleanField.Condition.Equals, false));

                if (null != filter)
                {
                    searchQuery.Query = Job.ISearch.AND(searchQuery.Query, filter);
                }
                jobList = new Collection<Job>(Job.Search(searchQuery, this.Conn));


                foreach (Job job in jobList)
                {
                    foreach (ActivityInstance actInst in job.ActivityInstances)
                    {
                        try
                        {

                            if (actInst.Activity.Owner.Equals(this))
                            {
                                jobListForOwner.Add(job);
                            }
                        }
                        catch (System.Security.SecurityException)
                        {
                            // Ignore: User does not have permission for the Worklfow.
                        }

                    }

                    // Add the JobSchedule if current user Schedules the job
                    if (((IObject)job.ScheduledBy).ID.Equals(((IObject)this).ID))
                    {
                        if (!jobListForOwner.Contains(job))
                        {
                            jobListForOwner.Add(job);
                        }
                    }
                }
            }
            catch (RecordNotFoundException)
            {
            }
            return jobListForOwner;
        }

        /// <summary>
        /// Retrieve the completed jobs for the user from the registry.
        /// </summary>
        /// <param name="filter">The additional search filter.</param>
        /// <returns>Collection of completed jobs.</returns>
        public Collection<Job> GetCompletedJobs(Job.ISearch.ISearchClause filter)
        {
            Collection<Job> jobList = null;
            Collection<Job> jobListForOwner = new Collection<Job>();
            try
            {

                Job.ISearch searchQuery = Job.ISearch.Create();
                Job.ISearch.ISearchClause clause = Job.ISearch.AND(
                                                       Job.ISearch.OR(
                                                           Job.ISearch.Status(EnumFieldBase.Condition.Equals, JobStatus.Aborted),
                                                           Job.ISearch.Status(EnumFieldBase.Condition.Equals, JobStatus.Completed)
                                                       ),
                                                       Job.ISearch.IsDeleted(BooleanField.Condition.Equals, false));
                if (null != filter)
                {
                    searchQuery.Query = Job.ISearch.AND(clause, filter);
                }
                else
                {
                    searchQuery.Query = clause;
                }
                jobList = new Collection<Job>(Job.Search(searchQuery, this.Conn));

                foreach (Job job in jobList)
                {
                    foreach (ActivityInstance actInst in job.ActivityInstances)
                    {
                        try
                        {

                            if (actInst.Activity.Owner.Equals(this))
                            {
                                jobListForOwner.Add(job);
                            }
                        }
                        catch (System.Security.SecurityException)
                        {
                            // Ignore: User does not have permission for the Worklfow.
                        }
                    }
                    // Add the JobSchedule if current user Schedules the job
                    if (((IObject)job.ScheduledBy).ID.Equals(((IObject)this).ID))
                    {
                        if (!jobListForOwner.Contains(job))
                        {
                            jobListForOwner.Add(job);
                        }
                    }

                }
            }
            catch (RecordNotFoundException)
            {
            }
            return jobListForOwner;
        }

        /// <summary>
        /// Gets all scheduled jobs.
        /// </summary>
        /// <param name="filter">The additional search filter.</param>
        /// <returns>Collection of scheduled jobs for the user.</returns>
        public Collection<JobSchedule> GetAllScheduledJobs(JobSchedule.ISearch.ISearchClause filter)
        {
            Collection<JobSchedule> schedules = null;
            Collection<JobSchedule> jobScheduldeForOwner = new Collection<JobSchedule>();
            try
            {
                JobSchedule.ISearch searchQuery = JobSchedule.ISearch.Create();
                if (null == filter)
                {
                    searchQuery.Query = JobSchedule.ISearch.Status(EnumFieldBase.Condition.NotEquals, ScheduleStatus.Cancelled);
                }
                else
                {
                    searchQuery.Query = JobSchedule.ISearch.AND(
                                            JobSchedule.ISearch.Status(EnumFieldBase.Condition.NotEquals, ScheduleStatus.Cancelled),
                                            filter);
                }

                schedules = new Collection<JobSchedule>(JobSchedule.Search(searchQuery, this.Conn));

                foreach (JobSchedule jobSchedulde in schedules)
                {
                    if (jobSchedulde.Template != null)
                    {
                        foreach (ActivityInstance actInst in jobSchedulde.Template.ActivityInstances)
                        {
                            try
                            {
                                if (actInst.Activity.Owner.Equals(this))
                                {
                                    jobScheduldeForOwner.Add(jobSchedulde);
                                }
                            }
                            catch (System.Security.SecurityException)
                            {
                                // Ignore: User does not have permission for the Worklfow.
                            }
                        }
                    }

                    // Add the JobSchedule if current user Schedules the job
                    if (((IObject)jobSchedulde.ScheduledBy).ID.Equals(((IObject)this).ID))
                    {
                        if (!jobScheduldeForOwner.Contains(jobSchedulde))
                        {
                            jobScheduldeForOwner.Add(jobSchedulde);
                        }
                    }
                }


            }
            catch (RecordNotFoundException)
            {
            }

            return jobScheduldeForOwner;
        }

        # region CommonSearches
        public sealed class CommonSearches
        {

            private CommonSearches()
            {
            }

            /// <summary>
            /// Fetches all non deleted Users .
            /// </summary>
            /// <param name="connection">Registry connectionection.</param>
            /// <returns>Collection of Users of type workflow.</returns>
            public static Collection<User> GetAllUsers(Connection connection)
            {
                #region Validation of Arguments

                if (null == connection)
                {
                    throw new ArgumentNullException("connection");
                }

                #endregion
                Collection<User> allUsers = null;
                try
                {
                    User.ISearch searchQuery = User.ISearch.Create();

                    searchQuery.Query = User.ISearch.AND(
                        User.ISearch.Name(StringField.Condition.NotEquals, SYSTEMUSER),
                        User.ISearch.Name(StringField.Condition.NotEquals, ANONYMOUS),
                        User.ISearch.IsDeleted(BooleanField.Condition.Equals, false));
                    allUsers = new Collection<User>(User.Search(searchQuery, connection));
                }
                catch (RecordNotFoundException)
                {
                    allUsers = new Collection<User>();
                }
                return allUsers;
            }

            /// <summary>
            /// Get all active and non deleted user  
            /// </summary>
            /// <param name="userName">UserNames</param>
            /// <param name="connection">Registry connectionection.</param>
            /// <returns>Collection of Users of type workflow.</returns>
            public static Collection<User> GetAllActiveUsers(Connection connection)
            {
                #region Validation of Arguments

                if (null == connection)
                {
                    throw new ArgumentNullException("connection");
                }

                #endregion
                Collection<User> allUsers = null;
                try
                {
                    User.ISearch searchQuery = User.ISearch.Create();
                    searchQuery.Query = User.ISearch.AND(
                        User.ISearch.Name(StringField.Condition.NotEquals, SYSTEMUSER),
                               User.ISearch.Name(StringField.Condition.NotEquals, ANONYMOUS),
                        User.ISearch.Enabled(BooleanField.Condition.Equals, true),
                        User.ISearch.IsDeleted(BooleanField.Condition.Equals, false));
                    allUsers = new Collection<User>(User.Search(searchQuery, connection));
                }
                catch (RecordNotFoundException)
                {
                    allUsers = new Collection<User>();
                }

                return allUsers;
            }

            /// <summary>
            /// Fetches all active Users other than parameter userName  
            /// </summary>
            /// <param name="userId">UserId</param>
            /// <param name="connection">Registry connectionection.</param>
            /// <returns>Collection of Users of type workflow.</returns>
            public static Collection<User> GetAllUserByFilter(Guid userId, Connection connection)
            {
                #region Validation of Arguments

                if (null == connection)
                {
                    throw new ArgumentNullException("connection");
                }

                #endregion
                Collection<User> allUsers = new Collection<User>();
                try
                {

                    User deletedUser = User.Load(userId, connection);
                    if (deletedUser != null)
                    {
                        SystemRole.ISearch searchQuery = SystemRole.ISearch.Create();
                        SystemRole userRole = User.CommonSearches.GetHighPriorityBultinRole(deletedUser, connection);
                        if (userRole != null)
                        {
                            switch (userRole.BuiltinRole)
                            {
                                case SystemBuiltinRoleType.Administrators:
                                case SystemBuiltinRoleType.Services:
                                    {
                                        searchQuery.Query = SystemRole.ISearch.OR(
                                        SystemRole.ISearch.BuiltinRole(EnumFieldBase.Condition.Equals, SystemBuiltinRoleType.Administrators),
                                        SystemRole.ISearch.BuiltinRole(EnumFieldBase.Condition.Equals, SystemBuiltinRoleType.Services));
                                        break;
                                    }
                                case SystemBuiltinRoleType.Users:
                                    {
                                        searchQuery.Query = SystemRole.ISearch.OR(
                                       SystemRole.ISearch.BuiltinRole(EnumFieldBase.Condition.Equals, SystemBuiltinRoleType.Administrators),
                                       SystemRole.ISearch.BuiltinRole(EnumFieldBase.Condition.Equals, SystemBuiltinRoleType.Services),
                                       SystemRole.ISearch.BuiltinRole(EnumFieldBase.Condition.Equals, SystemBuiltinRoleType.Users));
                                        break;
                                    }

                                case SystemBuiltinRoleType.Guests:
                                    {
                                        searchQuery.Query =
                                     SystemRole.ISearch.BuiltinRole(EnumFieldBase.Condition.NotEquals, SystemBuiltinRoleType.None);
                                        break;
                                    }

                            }
                        }
                        else
                        {
                            searchQuery.Query = SystemRole.ISearch.BuiltinRole(EnumFieldBase.Condition.NotEquals, SystemBuiltinRoleType.None);
                        }

                        IEnumerable<SystemRole> allRoles = new Collection<SystemRole>(SystemRole.Search(searchQuery, connection)).Where
                        (p => (p.MemberUserPrincipal != null
                            && p.MemberUserPrincipal.IsDeleted == false
                            && p.MemberUserPrincipal.Enabled == true
                            && !((IObject)p.MemberUserPrincipal).ID.Equals(userId)
                            && !p.MemberUserPrincipal.Name.Equals(SYSTEMUSER, StringComparison.OrdinalIgnoreCase)
                             && !p.MemberUserPrincipal.Name.Equals(ANONYMOUS, StringComparison.OrdinalIgnoreCase))

                            || (p.MemberGroupPrincipal != null
                            && p.MemberGroupPrincipal.IsDeleted == false
                            && p.MemberGroupPrincipal.Enabled == true));

                        foreach (SystemRole roles in allRoles)
                        {
                            if (roles.MemberUserPrincipal != null && !allUsers.Contains(roles.MemberUserPrincipal))
                            {
                                allUsers.Add(roles.MemberUserPrincipal);
                            }

                            if (roles.MemberGroupPrincipal != null)
                            {
                                foreach (User user in roles.MemberGroupPrincipal.Users)
                                {
                                    if (!allUsers.Contains(user) && !((IObject)user).ID.Equals(userId) && user.Enabled && !user.IsDeleted)
                                    {
                                        allUsers.Add(user);
                                    }
                                }
                            }
                        }
                    }
                }
                catch (RecordNotFoundException)
                {

                }

                return allUsers;
            }


            public static SystemRole GetHighPriorityBultinRole(User user, Connection connection)
            {
                #region Validation of Arguments

                if (null == user)
                {
                    throw new ArgumentNullException("connection");
                }

                if (null == connection)
                {
                    throw new ArgumentNullException("connection");
                }
                #endregion

                try
                {
                    SystemRole adminRole = user.SystemRoles.FirstOrDefault(p => p.BuiltinRole.Equals(SystemBuiltinRoleType.Administrators));

                    if (adminRole != null)
                    {
                        return adminRole;
                    }
                    else
                    {
                        List<SystemRole> userGroupAdminRole = (
                                              from grp in user.Groups
                                              where grp.IsDeleted == false && grp.Enabled == true
                                              from role in grp.SystemRoles
                                              where role.BuiltinRole.Equals(SystemBuiltinRoleType.Administrators)
                                              select role).ToList();

                        if (userGroupAdminRole.Count > 0)
                        {
                            return userGroupAdminRole[0];
                        }
                    }

                    SystemRole serviceRole = user.SystemRoles.FirstOrDefault(p => p.BuiltinRole.Equals(SystemBuiltinRoleType.Services));
                    if (serviceRole != null)
                    {
                        return serviceRole;
                    }
                    else
                    {
                        List<SystemRole> userGroupServiceRole = (
                         from grp in user.Groups
                         where grp.IsDeleted == false && grp.Enabled == true
                         from role in grp.SystemRoles
                         where role.BuiltinRole.Equals(SystemBuiltinRoleType.Services)
                         select role).ToList();
                        if (userGroupServiceRole.Count > 0)
                        {
                            return userGroupServiceRole[0];
                        }
                    }

                    SystemRole userRole = user.SystemRoles.FirstOrDefault(p => p.BuiltinRole.Equals(SystemBuiltinRoleType.Users));

                    if (userRole != null)
                    {
                        return userRole;
                    }
                    else
                    {
                        List<SystemRole> userGroupUserRole = (
                                           from grp in user.Groups
                                           where grp.IsDeleted == false && grp.Enabled == true
                                           from role in grp.SystemRoles
                                           where role.BuiltinRole.Equals(SystemBuiltinRoleType.Users)
                                           select role).ToList();
                        if (userGroupUserRole.Count > 0)
                        {
                            return userGroupUserRole[0];
                        }
                    }

                    SystemRole guestRole = user.SystemRoles.FirstOrDefault(p => p.BuiltinRole.Equals(SystemBuiltinRoleType.Guests));


                    if (guestRole != null)
                    {
                        return guestRole;
                    }
                    else
                    {
                        List<SystemRole> userGroupGuestRole = (
                                           from grp in user.Groups
                                           where grp.IsDeleted == false && grp.Enabled == true
                                           from role in grp.SystemRoles
                                           where role.BuiltinRole.Equals(SystemBuiltinRoleType.Guests)
                                           select role).ToList();
                        if (userGroupGuestRole.Count > 0)
                        {
                            return userGroupGuestRole[0];
                        }
                    }
                }
                catch (RecordNotFoundException)
                {
                    // Ignore this Exception
                }

                return null;
            }

            /// <summary>
            /// Searches  the UsersCredentials .based on parameter userName  
            /// </summary>
            /// <param name="userName">UserNames</param>
            /// <param name="connection">Registry connectionection.</param>
            /// <returns>return true if credentila exists</returns>
            public static bool UserCredentialExistInRegistry(string userName, Connection connection)
            {

                #region Validation of Arguments

                if (null == connection)
                {
                    throw new ArgumentNullException("connection");
                }

                List<UserCredential> allUserCredential = new List<UserCredential>();

                #endregion

                try
                {
                    allUserCredential = UserCredential.LoadAll(connection);
                    UserCredential userCredential = allUserCredential.FirstOrDefault(p => p.Credential.ToLower().Equals(userName.ToLower())
                        && p.User.Enabled == true && p.User.IsDeleted == false);
                    if (userCredential != null)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }

                }
                catch (RecordNotFoundException)
                {
                }

                return false;
            }

            /// <summary>
            /// Check the user name exists in the registry
            /// Checks only the non deleted user
            /// </summary>
            /// <param name="id">Guid</param>
            /// <param name="userName"></param>
            /// <param name="connection"></param>
            /// <returns></returns>
            public static bool UserExistInRegistry(Guid id, string userName, Connection connection)
            {
                #region Validation of Arguments

                if (null == connection)
                {
                    throw new ArgumentNullException("connection");
                }

                Collection<User> users = new Collection<User>();

                #endregion

                try
                {
                    User.ISearch searchQuery = User.ISearch.Create();
                    searchQuery.Query = User.ISearch.AND(
                        User.ISearch.Name(StringField.Condition.Equals, userName),
                        User.ISearch.IsDeleted(BooleanField.Condition.Equals, false));

                    users = new Collection<User>(User.Search(searchQuery, connection));
                    int count;
                    if (!id.Equals(Guid.Empty))
                    {
                        count = (from p in users where !((IObject)p).ID.Equals(id) select p).Count();
                    }
                    else
                    {
                        count = (from p in users select p).Count();
                    }

                    return count > 0;
                    //}
                }
                catch (RecordNotFoundException)
                {
                    users = null;
                }

                return false;
            }

            /// <summary>
            /// Fetches all enabled Users .
            /// </summary>
            /// <param name="connection">Registry connectionection.</param>
            /// <returns>Collection of enabled users.</returns>
            public static Collection<User> GetAllEnabledUsers(Connection connection)
            {
                #region Validation of Arguments
                if (null == connection)
                {
                    throw new ArgumentNullException("connection");
                }
                #endregion
                Collection<User> enabledUsers = new Collection<User>();
                try
                {
                    User.ISearch searchQuery = User.ISearch.Create();
                    searchQuery.Query = User.ISearch.AND(
                    User.ISearch.Name(StringField.Condition.NotEquals, SYSTEMUSER),
                     User.ISearch.Name(StringField.Condition.NotEquals, ANONYMOUS),
                    User.ISearch.IsDeleted(BooleanField.Condition.Equals, false),
                    User.ISearch.Enabled(BooleanField.Condition.Equals, true));
                    enabledUsers = new Collection<User>(User.Search(searchQuery, connection));
                }
                catch (RecordNotFoundException)
                {
                    enabledUsers = new Collection<User>();
                }
                return enabledUsers;
            }


            /// <summary>
            /// Counts all the active Users 
            /// </summary>
            /// <param name="connection">Registry connectionection.</param>
            /// <returns>count of Admin users </returns>
            public static int GetAllAdminUsersCount(Connection connection, Guid userId)
            {
                #region Validation of Arguments

                if (null == connection)
                {
                    throw new ArgumentNullException("connection");
                }

                #endregion
                Collection<SystemRole> allAdminRoles = null;
                List<ISecurityPrincipal> adminUsers = new List<ISecurityPrincipal>();

                try
                {
                    SystemRole.ISearch searchQuery = SystemRole.ISearch.Create();
                    searchQuery.Query = SystemRole.ISearch.BuiltinRole(EnumFieldBase.Condition.Equals, SystemBuiltinRoleType.Administrators);
                    allAdminRoles = new Collection<SystemRole>(SystemRole.Search(searchQuery, connection));
                    foreach (SystemRole sys in allAdminRoles)
                    {
                        if (sys.MemberUserPrincipal != null && !((IObject)sys.MemberUserPrincipal).ID.Equals(userId)
                            && sys.MemberUserPrincipal.Enabled && sys.MemberUserPrincipal.IsDeleted == false)
                        {
                            if (!sys.MemberUserPrincipal.Name.Equals(SYSTEMUSER, StringComparison.OrdinalIgnoreCase))
                            {
                                adminUsers.Add(sys.MemberUserPrincipal);
                            }
                        }

                        if (sys.MemberGroupPrincipal != null
                                && sys.MemberGroupPrincipal.IsDeleted == false
                                && sys.MemberGroupPrincipal.Enabled == true)
                        {
                            foreach (User user in sys.MemberGroupPrincipal.Users)
                            {
                                if (!((IObject)user).ID.Equals(userId)
                                    && user.Enabled
                                    && user.IsDeleted == false
                                    && !adminUsers.Contains(user)
                                    && !user.Name.Equals(SYSTEMUSER, StringComparison.OrdinalIgnoreCase))
                                {
                                    adminUsers.Add(user);
                                }

                            }
                        }

                    }
                }
                catch (RecordNotFoundException)
                {

                }

                return adminUsers.Count;
            }
        }
        #endregion
    }
}
